'use strict';
// const xlsx = require("node-xlsx");
const xlsx = require("xlsx");
const fs = require('fs');
const Service = require('egg').Service;
// const path = require('path');

// const resideStatusMap = new Map([
//   ['未入寝', -1],
//   ['在住', 1],
//   ['退寝', 2],
//   ['暂时离校', 3],
//   ['待退寝', 4]
// ]);

const studyStatusMap = new Map([
  ['未报到', -1],
  ['在读', 1],
  ['毕业', 2]
]);

class StudentService extends Service {
  // 添加一个学生
  async insertOneStudent(data) {
    const { ctx } = this;
    const errors = await this.checkStudentData(data);
    if (errors) {
      return {
        errcode: 1,
        msg: errors.join(',')
      };
    }

    await ctx.model.Student.create({
      student_num: data.student_num,
      student_password: data.student_password,
      student_name: data.student_name,
      student_sex: data.student_sex,
      student_class: data.student_class,
      dorm_id: null,
      checkin_time: null,
      student_address: data.student_address,
      student_major: data.student_major,
      enroll_date: data.enroll_date,
      reside_status: -1,
      study_status: data.study_status,
      identity: 2,
    });
    return { errcode: 0 };
  }

  // 添加多个学生
  async insertManyStudent(data) {
    const { ctx } = this;
    return await ctx.model.Student.create(data);
  }

  // 根据Id修改学生信息
  async updateOneStudentById(data) {
    const { ctx } = this;
    const newData = {
      student_name: data.student_name,
      student_sex: data.student_sex,
      student_address: data.student_address,
      student_class: data.student_class,
      student_major: data.student_major,
      enroll_date: data.enroll_date,
      study_status: data.study_status
    };
    if (data.student_password) {
      newData.student_password = data.student_password;
    }
    return await ctx.model.Student.findByIdAndUpdate(data._id, newData);
  }

  //  根据学号查找学生的信息
  async findStudentByNum(num) {
    const { ctx } = this;
    return await ctx.model.Student.findOne({
      student_num: num,
    }).populate('dorm_id');
  }

  // 根据_id 查找学生
  async findOneById(_id) {
    const { ctx } = this;
    return ctx.model.Student.findById(_id).populate('dorm_id');
  }

  // 根据_id删除一个学生
  async removeOneById(_id) {
    const { ctx } = this;
    const checkRes = await this.beforeRemoveStudent(_id);
    if (checkRes.errcode) {
      return {
        errcode: 1,
        msg: checkRes.errorInfo.errors.map(item => item.msg).join(',')
      };
    }
    await ctx.model.Student.deleteOne({ _id, });
    return { errcode: 0 };
  }

  // 检查学生的数据是否合法
  async checkStudentData(item) {
    const errors = [];
    if (!item.student_num) {
      errors.push('学号为空');
    }
    if (await this.findStudentByNum(item.student_num)) {
      errors.push('学号已存在');
    }
    if (!item.student_password) {
      errors.push('密码为空');
    }
    if (!item.student_name) {
      errors.push('学生姓名为空');
    }
    if (!item.student_sex) {
      errors.push('学生性别');
    }
    // if (!item.dorm_id) {
    //   errors.push('宿舍号不存在，请先新建宿舍！');
    // }
    if (!item.student_class) {
      errors.push('班级为空');
    }
    if (!item.student_major) {
      errors.push('专业为空');
    }
    if (!item.enroll_date) {
      errors.push('入学日期为空');
    }
    // if (!item.reside_status) {
    //   errors.push('居住状态为空');
    // }
    if (!item.study_status) {
      errors.push('学业状态为空');
    }
    if (errors.length) {
      return errors;
    }
    return null;
  }

  // 转换Excel学生数据
  async convertStudentData(item) {
    const data = { ...item };
    data.student_sex = data.student_sex ? data.student_sex === '男' ? 1 : 2 : null;
    // data.dorm_id = await this.ctx.service.dorm.findDormByNumber(data.dorm_id);
    // data.reside_status = resideStatusMap.get(data.reside_status);
    data.study_status = studyStatusMap.get(data.study_status);
    return data;
  }

  // 解析上传Excel文件，批量添加学生
  async insertByXlsx(staticPath) {
    const { ctx } = this;
    // const staticPath = await ctx.service.common.uploadFile();
    // staticPath = path.normalize(staticPath);
    const filePath = ctx.helper.convertStaticToAbsolutePath(staticPath);
    try {
      fs.accessSync(filePath);
    } catch (err) {
      throw "该文件已不存在，请重新上传";
    }
    try {
      const workbook = xlsx.readFile(filePath);
      const worksheet = workbook.Sheets[workbook.SheetNames[0]];
      const xlsxRes = xlsx.utils.sheet_to_json(worksheet, { header: 1 });

      const xlsxData = xlsxRes.slice(1);
      const errList = [];
      const resList = [];
      for (const item of xlsxData) {
        const rawData = {
          student_num: item[0],
          student_password: item[1],
          student_name: item[2],
          student_sex: item[3],
          student_class: +item[8],
          dorm_id: null,
          checkin_time: null,
          student_address: item[4],
          student_major: item[5],
          enroll_date: item[6],
          reside_status: -1,
          study_status: item[7],
          identity: 2,
        };
        const studentData = await this.convertStudentData(rawData);
        const checkRes = await this.checkStudentData(studentData);
        if (checkRes) {
          rawData.error = checkRes;
          errList.push(rawData);
        } else {
          resList.push(studentData);
        }
      }

      if (errList.length) {
        return errList;
      }
      await this.insertManyStudent(resList);
      return null;
    } catch (err) {
      console.log(err);
      throw "解析xlsx格式错误，请重新下载模板！";
    } finally {
      await ctx.service.common.delStaticFile(staticPath);
    }
  }

  // 校验学生的学号密码
  async authStudent(account, password) {
    const student = await this.findStudentByNum(account);
    if (!student) {
      // 查无此人
      return {
        errcode: 1,
        msg: "学号不存在"
      };
    }
    if (student.student_password !== password) {
      // 密码错误
      return {
        errcode: -1,
        msg: "密码错误"
      };
    }
    return {
      errcode: 0,
      msg: "success",
      data: student
    };
  }

  // 查询学生
  async searchStudent(conditions) {
    const ctx = this.ctx;
    const keyword = new RegExp(conditions.keyword, 'i');
    const page = conditions.page || 1;
    const pageSize = conditions.pageSize || 10;
    const query = {
      $or: [
        { student_name: { $regex: keyword } },
        { student_address: { $regex: keyword } },
        { student_major: { $regex: keyword } },
        { student_num: { $regex: keyword } }
      ]
    };

    if (conditions.dorm_num) {
      const dormId = await ctx.service.dorm.fingObjectIdByNumber(conditions.dorm_num);
      query.dorm_id = { $eq: dormId, $ne: null };
    }

    if (conditions.sex) {
      query.student_sex = conditions.sex;
    }
    if (conditions.reside_status) {
      query.reside_status = conditions.reside_status;
    }

    const [list, total] = await Promise.all([
      ctx.model.Student.find(query)
        .select('-student_password')
        .sort('student_num')
        .populate('dorm_id', 'dorm_num')
        .skip((page - 1) * pageSize)
        .limit(pageSize),
      ctx.model.Student.find(query).count(),
    ]);

    return {
      list,
      paging: ctx.helper.getPaging(total, pageSize)
    };
  }

  // 删除学生前判断
  async beforeRemoveStudent(id) {
    const { ctx } = this;
    const student = await ctx.model.Student.findById(id).populate('dorm_id').select('-student_password');
    const errors = [];
    if (student.dorm_id) {
      errors.push({ errcode: 1, msg: "该学生已分配宿舍，请先退寝" });
    }
    if (errors.length) {
      return {
        errcode: 1,
        errorInfo: {
          errors,
          student: {
            student_num: student.student_num,
            student_name: student.student_name,
            dorm_num: student.dorm_id && student.dorm_id.dorm_num
          }
        }
      };
    }
    return {
      errcode: 0,
    };
  }

  // 批量删除学生
  async removeManyStudentById(students) {
    const { ctx } = this;
    const errorStudents = [];

    for (const studentId of students) {
      const checkRes = await this.beforeRemoveStudent(studentId);
      if (checkRes.errcode) {
        errorStudents.push(checkRes.errorInfo);
      }
    }

    if (errorStudents.length) {
      return {
        errcode: 1,
        errorStudents
      };
    }

    for (const studentId of students) {
      await ctx.model.Student.deleteOne({
        _id: studentId,
      });
    }
    return { errcode: 0 };
  }

  // 给一个学生分配宿舍
  async assignsDorm(data) {
    const { ctx } = this;

    const checkDormRes = await ctx.service.dorm.checkDormStudentCount(data.dorm_num);
    if (checkDormRes.errcode) {
      return checkDormRes;
    }
    const student = await ctx.model.Student.findById(data.student_id);
    if (!student) {
      return {
        errcode: 3,
        msg: "该学生已不存在"
      };
    }
    const dorm_id = checkDormRes.data.dorm_id;
    const checkin_time = dorm_id.equals(student.dorm_id) ? null : Date.now();
    student.dorm_id = dorm_id;
    student.reside_status = 1;
    if (checkin_time) {
      student.checkin_time = checkin_time;
    }
    await student.save();
    return { errcode: 0 };
  }

  // 批量分配宿舍
  async bulkAssignDorm(data) {
    const { ctx } = this;
    const students = data.students;
    const checkRes = await ctx.service.dorm.checkDormStudentCount(data.dorm_num);
    if (checkRes.errcode) {
      return checkRes;
    }
    const dorm_id = checkRes.data.dorm_id;
    const countData = checkRes.data;
    const remaining = countData.contain_count - countData.reside_count;
    if (students.length > remaining) {
      return { errcode: 3, msg: "宿舍剩余容纳人数不足于本次安排" };
    }

    for (const studentId of students) {
      const student = await ctx.model.Student.findById(studentId);
      student.dorm_id = dorm_id;
      student.reside_status = 1;
      student.checkin_time = Date.now();
      await student.save();
    }
    return { errcode: 0 };
  }

  // 办理退寝
  async setLeave(id) {
    const { ctx } = this;

    const student = await ctx.model.Student.findById(id);
    if (!student) {
      return {
        errcode: 3,
        msg: "该学生已不存在"
      };
    }

    if (!student.dorm_id) {
      return {
        errcode: 4,
        msg: "该学生还未分配宿舍"
      };
    }

    student.dorm_id = null;
    student.reside_status = 2;
    student.checkin_time = null;
    await student.save();
    return { errcode: 0 };
  }

  // 批量办理退寝
  async bulkSetLeave(data) {
    const { ctx } = this;
    const errorStudents = [];
    const students = data.students;
    for (const studentId of students) {
      const errors = [];
      const student = await ctx.model.Student.findById(studentId);
      if (!student) {
        errors.push("该学生已不存在");
      }
      if (student && !student.dorm_id) {
        errors.push("该学生还未分配宿舍");
      }
      errors.length && errorStudents.push({ student, errors });
    }

    if (errorStudents.length) {
      return {
        errcode: 1,
        errorStudents
      };
    }

    for (const studentId of students) {
      const student = await ctx.model.Student.findById(studentId);
      student.dorm_id = null;
      student.checkin_time = null;
      student.reside_status = 2;
      await student.save();
    }

    return { errcode: 0 };
  }

  // 学生提交退寝申请单
  async postLeaveForm(data) {
    const { ctx } = this;

    await ctx.model.LeaveDorm.create({
      student_id: data.id,
      contact: data.contact,
      reason: data.reason,
      edit_date: Date.now(),
      approval_date: null,
      approver: null,
      approval_status: -1
    });

    return { errcode: 0 };
  }

  // 学生查看已提交的退寝申请单
  async studentSubmittedLeaveForm(id) {
    const { ctx } = this;
    const data = await ctx.model.LeaveDorm.find({ student_id: id })
      .populate('approver', 'admin_name -_id')
      .sort('-edit_date');
    return { errcode: 0, data };
  }

  // 管理员查询左右的学生退寝申请表
  async searchLeaveForm(conditions) {
    const { ctx } = this;
    const page = conditions.page || 1;
    const pageSize = conditions.pageSize || 10;
    const query = {};
    if (conditions.status) {
      query.approval_status = conditions.status;
    }
    const [list, total] = await Promise.all([
      ctx.model.LeaveDorm.find(query)
        .sort('-edit_date')
        .populate('student_id', '-student_password')
        .populate('approver', 'admin_name -_id')
        .skip((page - 1) * pageSize)
        .limit(pageSize),
      ctx.model.LeaveDorm.find(query).count(),
    ]);

    return {
      list,
      paging: ctx.helper.getPaging(total, pageSize)
    };
  }

  // 同意退寝
  async agreeLeave(id, approver) {
    const { ctx } = this;
    const leaveForm = await ctx.model.LeaveDorm.findById(id);
    const studentId = leaveForm.student_id;
    const operationRes = await this.setLeave(studentId);
    if (operationRes.errcode) {
      return operationRes;
    }
    leaveForm.approval_status = 1;
    leaveForm.approval_date = Date.now();
    leaveForm.approver = approver;
    await leaveForm.save();
    return { errcode: 0 };
  }

  // 拒绝退寝
  async rejectLeave(id, approver) {
    const { ctx } = this;
    const leaveForm = await ctx.model.LeaveDorm.findById(id);
    leaveForm.approval_status = 2;
    leaveForm.approval_date = Date.now();
    leaveForm.approver = approver;
    await leaveForm.save();
    return { errcode: 0 };
  }
  // 删除退寝申请单
  async removeLeave(id) {
    const { ctx } = this;
    await ctx.model.LeaveDorm.deleteOne({ _id: id });
    return { errcode: 0 };
  }


  // 学生提交调整宿舍申请单
  async postAdjustForm(data) {
    const { ctx } = this;
    await ctx.model.AdjustDorm.create({
      student_id: data.id,
      target_dorm: data.target_dorm,
      reason: data.reason,
      edit_date: Date.now(),
      approval_date: null,
      approver: null,
      approval_status: -1
    });
    return { errcode: 0 };
  }

  // 学生查看已提交的调整宿舍申请单
  async studentSubmittedAdjustForm(id) {
    const { ctx } = this;
    const data = await ctx.model.AdjustDorm.find({ student_id: id })
      .populate('approver', 'admin_name -_id')
      .sort('-edit_date');
    return { errcode: 0, data };
  }

  // 管理员查询学生调整宿舍申请表
  async searchAdjustForm(conditions) {
    const { ctx } = this;
    const page = conditions.page || 1;
    const pageSize = conditions.pageSize || 10;
    const query = {};
    if (conditions.status) {
      query.approval_status = conditions.status;
    }
    const [list, total] = await Promise.all([
      ctx.model.AdjustDorm.find(query)
        .sort('-edit_date')
        .populate('student_id', '-student_password')
        .populate('approver', 'admin_name -_id')
        .skip((page - 1) * pageSize)
        .limit(pageSize),
      ctx.model.AdjustDorm.find(query).count(),
    ]);

    return {
      list,
      paging: ctx.helper.getPaging(total, pageSize)
    };
  }

  // 同意调整宿舍
  async agreeAdjust(id, approver) {
    const { ctx } = this;
    const adjustForm = await ctx.model.AdjustDorm.findById(id);
    const student_id = adjustForm.student_id;
    const dorm_num = adjustForm.target_dorm;
    const data = {
      dorm_num,
      student_id,
    };
    const operationRes = await this.assignsDorm(data);
    if (operationRes.errcode) {
      return operationRes;
    }
    adjustForm.approval_status = 1;
    adjustForm.approval_date = Date.now();
    adjustForm.approver = approver;
    await adjustForm.save();
    return { errcode: 0 };
  }

  // 拒绝调整宿舍
  async rejectAdjust(id, approver) {
    const { ctx } = this;
    const adjustForm = await ctx.model.AdjustDorm.findById(id);
    adjustForm.approval_status = 2;
    adjustForm.approval_date = Date.now();
    adjustForm.approver = approver;
    await adjustForm.save();
    return { errcode: 0 };
  }
  // 删除调整宿舍申请单
  async removeAdjust(id) {
    const { ctx } = this;
    await ctx.model.AdjustDorm.deleteOne({ _id: id });
    return { errcode: 0 };
  }

  // 填写离校登记表
  async editLeaveSchoolForm(data) {
    const { ctx } = this;
    data.edit_date = Date.now();
    data.student_id = data.id;
    await ctx.model.LeaveSchool.create(data);
    return { errcode: 0 };
  }

  // 删除离校登记表
  async delLeaveSchoolForm(id) {
    const { ctx } = this;
    await ctx.model.LeaveSchool.deleteOne({ _id: id });
    return { errcode: 0 };
  }

  // 查询离校登记表
  async searchLeaveSchoolForm(conditions) {
    const { ctx } = this;
    const page = conditions.page || 1;
    const pageSize = conditions.pageSize || 10;
    const startTime = conditions.startTime || -Infinity;
    const endTime = conditions.endTime || Infinity;
    const query = {
      edit_date: {
        $gte: startTime,
        $lte: endTime
      }
    };
    const [list, total] = await Promise.all([
      ctx.model.LeaveSchool.find(query)
        .sort('-edit_date')
        .populate('student_id', '-student_password')
        .skip((page - 1) * pageSize)
        .limit(pageSize),
      ctx.model.LeaveSchool.find(query).count(),
    ]);

    return {
      list,
      paging: ctx.helper.getPaging(total, pageSize)
    };
  }

  // 学生查看自己的离校登记表
  async findSelfLeaveSchoolForm(id) {
    const { ctx } = this;
    const data = await ctx.model.LeaveSchool.find({ student_id: id })
      .sort('-edit_date');
    return { errcode: 0, data };
  }

}

module.exports = StudentService;
